/*
 * Copyright 2009 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.splink.deepsplink.page {
	import org.splink.deepsplink.navigation.command.INavigationCommand;
	import org.splink.deepsplink.page.params.PageParameter;
	import org.splink.deepsplink.page.state.PageState;
	import org.splink.deepsplink.page.transition.DefaultHideStrategy;
	import org.splink.deepsplink.page.transition.DefaultShowStrategy;
	import org.splink.library.distributor.Distributor;
	import org.splink.library.distributor.Dtype;
	import org.splink.library.distributor.IDevent;
	import org.splink.library.distributor.IDistributor;
	import org.splink.library.logging.ILogger;
	import org.splink.library.logging.LogLevel;
	import org.splink.library.logging.LoggerProvider;
	import org.splink.library.queue.IQable;
	import org.splink.library.queue.QEvent;
	import org.splink.library.tree.Tree;

	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;

	/**
	 * <code>PageContainer</code> manages the state of an <code>IPage</code>
	 * and serves as a provider for operations and data the page needs to
	 * access.
	 * 
	 * @see org.splink.deepsplink.page.Page
	 * @author Max Kugland
	 */
	final internal class PageContainer implements IPageSupplier, IPageInternal {
		private static const _logger:ILogger = LoggerProvider.getLogger("deepsplink", PageContainer);
		private var _state : PageState;
		private var _id : String;
		private var _display : DisplayObjectContainer;
		private var _navigationCmd : INavigationCommand;
		private var _tree : Tree;
		private var _params : Array;
		private var _showStrategy : IQable;
		private var _hideStrategy : IQable;
		private var _distributor : Distributor;
		private var _title : String;
		private var _page : IPage;
		private var _previousState : PageState;

		/**
		 * Constructs a <code>PageContainer</code> and sets default show and hide strategies. 
		 * After instantiation it's state is <code>PageStates.INSTANTIATED_STATE</code>
		 * 
		 * @param id the id of the page
		 */
		public function PageContainer(id : String) {
			_id = id;
			_params = new Array();
			_display = new Sprite;
			_display.name = id;
			_distributor = new Distributor();
			setState(PageState.INSTANTIATED_STATE);
			_showStrategy = new DefaultShowStrategy;
			_hideStrategy = new DefaultHideStrategy;
		}

		/**
		 * @inheritDoc
		 */
		public function setPage(p : IPage) : void {
			_page = p;
		}

		/**
		 * @inheritDoc
		 */
		public function setTitle(t : String) : void {
			_title = t;
		}

		/**
		 * @inheritDoc
		 */
		public function get title() : String {
			return _title;
		}

		/**
		 * @inheritDoc
		 */
		public function setShowStrategy(showStrategy : IQable) : IQable {
			return _showStrategy = showStrategy;
		}

		/**
		 * @inheritDoc
		 */
		public function setHideStrategy(hideStrategy : IQable) : IQable {
			return _hideStrategy = hideStrategy;
		}

		/**
		 * @inheritDoc
		 */
		public function setTree(t : Tree) : void {
			_tree = t;
		}

		/**
		 * @inheritDoc
		 */
		public function get tree() : Tree {
			return _tree;
		}

		/**
		 * @inheritDoc
		 */
		public function setNavigationCommand(navigationCmd : INavigationCommand) : void {
			_navigationCmd = navigationCmd;
		}

		/**
		 * @inheritDoc
		 */
		public function get navigationCommand() : INavigationCommand {
			return _navigationCmd;
		}

		/**
		 * @inheritDoc
		 */
		public function setState(s : PageState) : void {
			_logger.log(LogLevel.TRACE, id + " " + s);
			_previousState = _state;
			_state = s;
		}

		/**
		 * @inheritDoc
		 */
		public function get id() : String {
			return _id;	
		}

		/**
		 * @inheritDoc
		 */
		public function get state() : PageState {
			return _state;
		}

		/**
		 * @inheritDoc
		 */
		public function get display() : DisplayObjectContainer {
			return _display;
		}

		/**
		 * @inheritDoc
		 */
		public function setParams(p : Array) : void {
			if(_params && p) {
				if((p.toString() == _params.toString())) {
					return;
				}
			
				_params = p;
				
				if(_state != PageState.INSTANTIATED_STATE && _state != PageState.FINALIZED_STATE) {
					_page.onParamsChanged(_params);
				}
			}
		}

		/**
		 * @inheritDoc
		 */
		public function getParamValueForKey(key : String) : String {
			for each (var param : PageParameter in _params) {
				if(param.key == key) {
					return param.value;
				}
			}
			return null;
		}

		/**
		 * @inheritDoc
		 */
		public function get params() : Array {
			return _params.concat();
		}

		/**
		 * @inheritDoc
		 */
		public function initialize() : void {
			_page.initialize();
		}

		/**
		 * @inheritDoc
		 */
		public function setInitialized() : void {
			if(_state == PageState.INITIALIZING_STATE) {
				distribute(new PageContainerEvent(this, PageContainerEvent.INITIALIZED, _id));
			}
		}

		/**
		 * @inheritDoc
		 */
		public function show() : void {
			if(_previousState == PageState.HIDING_STATE) {				_hideStrategy.finalize();
			}
			_showStrategy.register(QEvent.COMPLETE, onShown);
			_showStrategy.start();
		}

		private function onShown(e : QEvent) : void {
			_showStrategy.unregister(QEvent.COMPLETE, onShown);
			distribute(new PageContainerEvent(this, PageContainerEvent.SHOWN, _id));
		}

		/**
		 * @inheritDoc
		 */
		public function hide() : void {
			if(_previousState == PageState.SHOWING_STATE) {
				_showStrategy.finalize();
			}
			_hideStrategy.register(QEvent.COMPLETE, onHidden);
			_hideStrategy.start();
		}

		private function onHidden(e : QEvent) : void {
			_hideStrategy.unregister(QEvent.COMPLETE, onHidden);
			distribute(new PageContainerEvent(this, PageContainerEvent.HIDDEN, _id));
		}

		/**
		 * @inheritDoc
		 */
		public function finalize() : void {
			_page.finalize();
			setState(PageState.FINALIZED_STATE);
			_params.splice(0, _params.length);
			_distributor.finalize();
		}

		/**
		 * @inheritDoc
		 */
		public function distribute(event : IDevent) : void {
			_distributor.distribute(event);
		}

		/**
		 * @inheritDoc
		 */
		public function register(type : Dtype, fnc : Function, params : Object = null, priority : uint = uint.MIN_VALUE) : IDistributor {
			return _distributor.register(type, fnc, params, priority);
		}

		/**
		 * @inheritDoc
		 */
		public function unregister(type : Dtype, fnc : Function) : IDistributor {
			return _distributor.unregister(type, fnc);
		}
	}
}
